package edu.neumont.csc380.soap.util;

import java.math.BigInteger;
import java.security.Key;
import java.security.KeyFactory;
import java.util.Random;

import javax.crypto.Cipher;

import edu.neumont.csc380.hello.model.KeyPair;
import edu.neumont.csc380.hello.model.KeySet;


public class RSAGenerator {
	NumberManager nm = new NumberManager();
	BigInteger p = null;
	BigInteger q = null;

	/**
	 * Given two prime numbers, returns a KeySet containing PublicKey, PrivateKey, and IdentifyingInformation
	 * @param prime1
	 * @param prime2
	 * @param identifier
	 * @return
	 */
	public KeySet getKeys(int prime1, int prime2, String identifier)
	{
		p = BigInteger.valueOf(prime1);
		q = BigInteger.valueOf(prime2);
		
		BigInteger n = p.multiply(q);
		BigInteger phi = (p.subtract(BigInteger.ONE)).multiply((q.subtract(BigInteger.ONE)));
		BigInteger publicKey = BigInteger.probablePrime(5, new Random());
		BigInteger gcd = phi.gcd(publicKey);
		while (gcd.compareTo(BigInteger.ONE) != 0){
			publicKey = BigInteger.probablePrime(5, new Random());
			gcd = phi.gcd(publicKey);
		}
		
		BigInteger privateKey = publicKey.modInverse(phi);
		
		KeyPair pubKey = new KeyPair(publicKey.longValue(), n.longValue());
		KeyPair privKey = new KeyPair(privateKey.longValue(), n.longValue());
		
		return new KeySet(pubKey, privKey, identifier);
	}
	
	/**
	 * UNNECESSARY IN THIS IMPLEMENTATION
	 * @param message
	 * @param publicKey
	 * @return
	 */
	public long encryptMessage(byte[] message, KeyPair publicKey)
	{
		BigInteger msg = BigInteger.valueOf(1234567890);
		
		BigInteger key = BigInteger.valueOf(publicKey.getKey());
		BigInteger n = BigInteger.valueOf(publicKey.getN());
		
		msg = msg.modPow(key, n);
		return msg.longValue();
	}

	/**
	 * UNNECESSARY IN THIS IMPLEMENTATION
	 * @param message
	 * @param privateKey
	 * @return
	 */
	public long decryptMessage(long message, KeyPair privateKey)
	{
		BigInteger msg = BigInteger.valueOf(message);
		
		BigInteger key = BigInteger.valueOf(privateKey.getKey());
		BigInteger n = BigInteger.valueOf(privateKey.getN());
		
		msg = msg.modPow(key, n);
		
		return msg.longValue();
	}

	/**
	 * GETTERS AND SETTERS
	 */
	
	public void setP(int primeNum)
	{
		this.p = BigInteger.valueOf((long) primeNum);
	}
	public int getP()
	{
		return this.p.intValue();
	}
	public void setQ(int primeNum)
	{
		this.q = BigInteger.valueOf((long) primeNum);
	}
	public int getQ()
	{
		return this.q.intValue();
	}
}
